﻿using Windows.UI.Text;
using DimensionsHelper.Common.Contracts.Excel;
using DimensionsHelper.Common.Contracts.Excel.Options;
using Microsoft.UI.Text;
using UnderlineType = Microsoft.UI.Text.UnderlineType;

namespace DimensionsHelper.Client.WinUi.ViewModels;

public partial class ExcelRangeStyleViewModel : ObservableObject
{
    public ExcelRangeStyleViewModel()
    {
        FontFamily = FontHelper.DefaultFontFamily;
        FontFamilySource = FontFamily.Source;
        FontSize = FontHelper.DefaultFontSize;
        FontColor = Colors.Black;
        InteriorColor = Colors.White;
        ExcelUnderlineType = UnderLineType.Single;
        BorderStyle = BorderStyle.Thin;
        Foreground = new SolidColorBrush(Colors.Black);
        Background = new SolidColorBrush(Colors.White);
        NumberFormatLocal = string.Empty;
        HAlignLeft = true;
        VAlignCenter = true;
    }


    internal bool UpdatingInternal
    {
        get;
        private set;
    }


    [ObservableProperty]
    public partial FontFamily FontFamily { get; set; }


    public string FontFamilySource { get; private set; }


    [ObservableProperty]
    public partial double FontSize { get; set; }


    [ObservableProperty]
    public partial double PixelFontSize { get; set; }


    [ObservableProperty]
    public partial Color FontColor { get; set; }


    [ObservableProperty]
    public partial Color InteriorColor { get; set; }


    [ObservableProperty]
    public partial Brush Foreground { get; set; }


    [ObservableProperty]
    public partial Brush Background { get; set; }


    [ObservableProperty]
    public partial HorizontalAlignment HAlign { get; set; }


    [ObservableProperty]
    public partial VerticalAlignment Valign { get; set; }


    [ObservableProperty]
    public partial bool Bold { get; set; }


    [ObservableProperty]
    public partial FontWeight FontWeight { get; set; }


    [ObservableProperty]
    public partial bool Italic { get; set; }


    [ObservableProperty]
    public partial FontStyle FontStyle { get; set; }


    [ObservableProperty]
    public partial bool Underlined { get; set; }


    [ObservableProperty]
    public partial UnderLineType ExcelUnderlineType { get; set; }


    [ObservableProperty]
    public partial UnderlineType UnderlineType { get; set; }


    [ObservableProperty]
    public partial TextDecorations TextDecoration { get; set; }


    [ObservableProperty]
    public partial bool HAlignLeft { get; set; }


    [ObservableProperty]
    public partial bool HAlignCenter { get; set; }


    [ObservableProperty]
    public partial bool HAlignRight { get; set; }


    [ObservableProperty]
    public partial bool VAlignTop { get; set; }


    [ObservableProperty]
    public partial bool VAlignCenter { get; set; }


    [ObservableProperty]
    public partial bool VAlignBottom { get; set; }


    [ObservableProperty]
    public partial string NumberFormatLocal { get; set; }


    [ObservableProperty]
    public partial bool AddAroundBorder { get; set; }


    [ObservableProperty]
    public partial bool AddHorizontalBorder { get; set; }


    [ObservableProperty]
    public partial bool AddVerticalBorder { get; set; }


    [ObservableProperty]
    public partial BorderStyle BorderStyle { get; set; }


    [ObservableProperty]
    public partial bool Wrap { get; set; }


    [ObservableProperty]
    public partial TextWrapping TextWrapping
    {
        get;
        set;
    }


    private void SetInternal(Action setter)
    {
        if (UpdatingInternal)
        {
            return;
        }

        UpdatingInternal = true;
        setter();
        UpdatingInternal = false;
    }


    partial void OnFontSizeChanged(double value) => PixelFontSize = value / 72 * 96;


    partial void OnFontColorChanged(Color value) => Foreground = new SolidColorBrush(value);


    partial void OnInteriorColorChanged(Color value) => Background = new SolidColorBrush(value);


    partial void OnHAlignChanged(HorizontalAlignment value)
    {
        SetInternal(() =>
        {
            HAlignLeft = value == HorizontalAlignment.Left;
            HAlignCenter = value == HorizontalAlignment.Center;
            HAlignRight = value == HorizontalAlignment.Right;
        });
    }


    partial void OnHAlignLeftChanged(bool value)
    {
        SetInternal(() =>
        {
            HAlignLeft = true;
            HAlignCenter = false;
            HAlignRight = false;
            HAlign = HorizontalAlignment.Left;
        });
    }


    partial void OnHAlignCenterChanged(bool value)
    {
        SetInternal(() =>
        {
            if (value)
            {
                HAlignLeft = false;
                HAlignRight = false;
                HAlign = HorizontalAlignment.Center;
            }
            else
            {
                HAlignLeft = true;
                HAlignRight = false;
                HAlign = HorizontalAlignment.Left;
            }
        });
    }


    partial void OnHAlignRightChanged(bool value)
    {
        SetInternal(() =>
        {
            if (value)
            {
                HAlignLeft = false;
                HAlignCenter = false;
                HAlign = HorizontalAlignment.Right;
            }
            else
            {
                HAlignLeft = true;
                HAlignRight = false;
                HAlign = HorizontalAlignment.Left;
            }
        });
    }


    partial void OnValignChanged(VerticalAlignment value)
    {
        SetInternal(() =>
        {
            VAlignTop = value == VerticalAlignment.Top;
            VAlignCenter = value == VerticalAlignment.Center;
            VAlignBottom = value == VerticalAlignment.Bottom;
        });
    }


    partial void OnVAlignTopChanged(bool value)
    {
        SetInternal(() =>
        {
            VAlignTop = true;
            VAlignCenter = false;
            VAlignBottom = false;
            Valign = VerticalAlignment.Top;
        });
    }


    partial void OnVAlignCenterChanged(bool value)
    {
        SetInternal(() =>
        {
            if (value)
            {
                VAlignTop = false;
                VAlignBottom = false;
                Valign = VerticalAlignment.Center;
            }
            else
            {
                VAlignTop = true;
                VAlignBottom = false;
                Valign = VerticalAlignment.Top;
            }
        });
    }


    partial void OnVAlignBottomChanged(bool value)
    {
        SetInternal(() =>
        {
            if (value)
            {
                VAlignTop = false;
                VAlignCenter = false;
                Valign = VerticalAlignment.Bottom;
            }
            else
            {
                VAlignTop = true;
                VAlignCenter = false;
                Valign = VerticalAlignment.Top;
            }
        });
    }


    partial void OnBoldChanged(bool value) => FontWeight = value ? FontWeights.Bold : FontWeights.Normal;


    partial void OnItalicChanged(bool value) => FontStyle = value ? FontStyle.Italic : FontStyle.Normal;


    partial void OnUnderlinedChanged(bool value)
    {
        if (!value)
        {
            UnderlineType = UnderlineType.None;
            TextDecoration = TextDecorations.None;
        }
        else
        {
            UnderlineType = ExcelUnderlineType switch
            {
                UnderLineType.Single => UnderlineType.Single,
                UnderLineType.Double => UnderlineType.Double,
                _ => UnderlineType.None
            };

            TextDecoration = TextDecorations.Underline;
        }
    }


    partial void OnWrapChanged(bool value) => TextWrapping = value ? TextWrapping.Wrap : TextWrapping.NoWrap;


    partial void OnFontFamilyChanged(FontFamily value) => FontFamilySource = value.Source;


    public void LoadOption(FontStyleOptions source, IReportService reportService)
    {
        if (!string.IsNullOrEmpty(source.FontFamily))
        {
            if (FontHelper.TryGetFontFamily(source.FontFamily, out FontFamily? family))
            {
                FontFamily = family;
            }
            else
            {
                reportService.Warn(ResourceKeys.AppFontIsNotInstalledMessage.GetLocalized(), source.FontFamily);
            }
        }

        if (source.FontSize > 72 || source.FontSize < 6)
        {
            reportService.Warn(ResourceKeys.AppFontSizeIsNotValidMessage.GetLocalized(), source.FontSize);
        }
        else
        {
            FontSize = source.FontSize;
        }

        FontColor = source.FontColor.ToWinUiColor();
        Bold = source.FontType.HasFlag(FontType.Bold);
        Italic = source.FontType.HasFlag(FontType.Italic);
        Underlined = source.FontType.HasFlag(FontType.Underline);
    }


    public void LoadOption(RangeStyleOptions source, IReportService reportService)
    {
        LoadOption(source.Font, reportService);

        HAlign = source.HAlign switch
        {
            ExcelHAlign.Center => HorizontalAlignment.Center,
            ExcelHAlign.Right => HorizontalAlignment.Right,
            _ => HorizontalAlignment.Left
        };

        Valign = source.VAlign switch
        {
            ExcelVAlign.Center => VerticalAlignment.Center,
            ExcelVAlign.Bottom => VerticalAlignment.Bottom,
            _ => VerticalAlignment.Top
        };

        InteriorColor = source.InteriorColor.ToWinUiColor();
        NumberFormatLocal = source.NumberFormatLocal;

        AddAroundBorder = source.BorderPosition.HasFlag(BorderPosition.Around);
        AddHorizontalBorder = source.BorderPosition.HasFlag(BorderPosition.Horizontal);
        AddVerticalBorder = source.BorderPosition.HasFlag(BorderPosition.Vertical);
        BorderStyle = source.BorderStyle;
        Wrap = source.WrapText;
    }


    public bool TryWriteOption(FontStyleOptions options, IReportService reportService)
    {
        options.FontFamily = FontFamilySource;
        options.FontSize = (float)FontSize;
        options.FontColor = FontColor.ToExcelStyleColor(reportService);

        if (Bold)
        {
            options.FontType |= FontType.Bold;
        }

        if (Italic)
        {
            options.FontType |= FontType.Italic;
        }

        if (Underlined)
        {
            options.FontType |= FontType.Underline;
        }

        return true;
    }


    public bool TryWriteOption(RangeStyleOptions target, IReportService reportService)
    {
        target.InteriorColor = InteriorColor.ToExcelStyleColor(reportService);

        target.HAlign = HAlign switch
        {
            HorizontalAlignment.Center => ExcelHAlign.Center,
            HorizontalAlignment.Right => ExcelHAlign.Right,
            _ => ExcelHAlign.Left
        };

        target.VAlign = Valign switch
        {
            VerticalAlignment.Center => ExcelVAlign.Center,
            VerticalAlignment.Bottom => ExcelVAlign.Bottom,
            _ => ExcelVAlign.Top
        };

        target.NumberFormatLocal = NumberFormatLocal;

        if (AddAroundBorder)
        {
            target.BorderPosition |= BorderPosition.Around;
        }

        if (AddHorizontalBorder)
        {
            target.BorderPosition |= BorderPosition.Horizontal;
        }

        if (AddVerticalBorder)
        {
            target.BorderPosition |= BorderPosition.Vertical;
        }

        target.BorderStyle = BorderStyle;
        target.WrapText = Wrap;

        return TryWriteOption(target.Font, reportService);
    }
}